package com.calvin.android.notification;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import com.calvin.android.annotation.Notice;

public class NotificationCenter {

	public interface OnNoticeListener {
		public void 	onNotify(String notify, Object... argv);
	}

	private static NotificationCenter mShared;
	private Map<String, List<OnNoticeListener>> mNotifyMap;

	private NotificationCenter() {
		mNotifyMap = new HashMap<String, List<OnNoticeListener>>();
	}

	public static NotificationCenter shared() {
		return mShared == null ? (mShared = new NotificationCenter()) : mShared;
	}

	public void scanNotice(Object object) {
		if (null != object) {
			Method[] methods = object.getClass().getDeclaredMethods();
			for (Method method : methods) {
				Notice notice = method.getAnnotation(Notice.class);
				if (null != notice) {
					for (String key : notice.value()) {
						addNotice(key, new NoticeListener(object, method));
					}
				}
			}
		}
	}

	public void addNotice(String notice, OnNoticeListener noticeListener) {
		if (!mNotifyMap.containsKey(notice)) {
			mNotifyMap.put(notice, new LinkedList<OnNoticeListener>());
		}
		mNotifyMap.get(notice).add(noticeListener);
	}

	public void removeNotice(String notice) {
		if (mNotifyMap.containsKey(notice)) {
			mNotifyMap.get(notice).clear();
		}
	}

	public void removeNotice(String notice, OnNoticeListener notifyListener) {
		if (mNotifyMap.containsKey(notice)) {
			mNotifyMap.get(notice).remove(notifyListener);
		}
	}

	public void postNotice(String notice, Object... argv) {
		if (mNotifyMap.containsKey(notice)) {
			Iterator<OnNoticeListener> iterator = mNotifyMap.get(notice).iterator();
			while (iterator.hasNext()) {
				iterator.next().onNotify(notice, argv);
			}
		}
	}

	class NoticeListener implements OnNoticeListener {
		private Object mTarget;
		private Method mMethod;

		public NoticeListener(Object target, Method method) {
			mTarget = target;
			mMethod = method;
		}

		@Override
		public void onNotify(String notify, Object... argv) {
			try {
				mMethod.invoke(mTarget, new Object[] { argv });
			} catch (Exception e) {
				e.printStackTrace();
			}
		}

	}
}
